home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xconq / side.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  13KB  |  525 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. #pragma comment(exestr, "@(#) side.c 12.1 95/05/09 ")
  6.  
  7. /* RCS $Header: side.c,v 1.2 88/07/18 22:07:28 shebs Exp $ */
  8.  
  9. /* The "side" structure is the repository of information about players. */
  10. /* Surprisingly, there is not much code to manipulate side directly.  */
  11. /* Viewing code is somewhat tricky, since any hex may be viewed by any */
  12. /* number of sides at once. */
  13.  
  14. #include "config.h"
  15. #include "misc.h"
  16. #include "dir.h"
  17. #include "period.h"
  18. #include "side.h"
  19. #include "unit.h"
  20. #include "map.h"
  21.  
  22. Side sides[MAXSIDES];  /* array containing all sides (not very many) */
  23. Side *sidelist;        /* head of list of all sides */
  24. Side *tmpside;         /* temporary used in many places */
  25.  
  26. int numsides;          /* number of sides in the game */
  27.  
  28. char *reasonnames[] = REASONNAMES;  /* names of columns in unit record */
  29.  
  30. /* Reset any side structures that need it. */
  31.  
  32. init_sides()
  33. {
  34.     int i;
  35.  
  36.     for (i = 0; i < MAXSIDES; ++i) {
  37.     sides[i].name = NULL;
  38.     }
  39.     sidelist = NULL;
  40.     numsides = 0;
  41. }
  42.  
  43. /* Create an object representing a side. Checking to make sure all human */
  44. /* players have displays has been done by now, so problems mean bugs. */
  45.  
  46. Side *
  47. create_side(name, person, host)
  48. char *name, *host;
  49. bool person;
  50. {
  51.     int s, i;
  52.     Side *newside;
  53.  
  54.     /* Can't have humans without displays */
  55.     if (person && host == NULL) abort();
  56.     if (name == NULL) name = "???";
  57.     for (s = 0; s < MAXSIDES; ++s) {
  58.     if (sides[s].name == NULL) {
  59.         newside = &(sides[s]);
  60.         newside->name = copy_string(name);
  61.         newside->humanp = person;
  62.         if (host == NULL || strcmp(host, "*") == 0) {
  63.         newside->host = NULL;
  64.         } else {
  65.         newside->host = copy_string(host);
  66.         }
  67.         newside->lost = FALSE;
  68.         for_all_unit_types(i) {
  69.         newside->counts[i] = 1;
  70.         newside->units[i] = 0;
  71.         newside->building[i] = 0;
  72.         }
  73.         for_all_resource_types(i) {
  74.         newside->resources[i] = 0;
  75.         }
  76.         newside->showmode = BORDERHEX;
  77.         newside->itertime = 100;
  78.         newside->view =
  79.         (unsigned char *) 
  80.             malloc(world.width*world.height*sizeof(unsigned char));
  81.         newside->coverage =
  82.         (short *) malloc(world.width*world.height*sizeof(short));
  83.         init_view(newside);
  84.         newside->graphical = GRAPHICAL;
  85.         newside->display = 0L;
  86.         init_requests(newside);
  87.         link_in_side(newside);
  88.         ++numsides;
  89.         return newside;
  90.     }
  91.     }
  92.     fprintf(stderr, "Cannot have more than %d sides total!\n", MAXSIDES);
  93.     abort();
  94. }
  95.  
  96. /* Add the new side to the end of the list of sides - this keeps our */
  97. /* list traversals going from top to bottom (the things we do to keep */
  98. /* users happy...). */
  99.  
  100. link_in_side(side)
  101. Side *side;
  102. {
  103.     Side *head, *last;
  104.  
  105.     if (sidelist == NULL) {
  106.     sidelist = side;
  107.     } else {
  108.     for_all_sides(head) {
  109.         if (head->next == NULL) last = head;
  110.     }
  111.     last->next = side;
  112.     }
  113.     side->next = NULL;
  114. }
  115.  
  116. /* Initialize basic viewing structures for a side, in preparation for the */
  117. /* placement of units. */
  118.  
  119. init_view(side)
  120. Side *side;
  121. {
  122.     int x, y, cov, seen;
  123.  
  124.     cov = (period.allseen ? 100 : 0);
  125.     seen = ((period.allseen || world.known) ? EMPTY : UNSEEN);
  126.     for (x = 0; x < world.width; ++x) {
  127.     for (y = 0; y < world.height; ++y) {
  128.         set_cover(side, x, y, cov);
  129.         set_side_view(side, x, y, seen);
  130.     }
  131.     }
  132.     side->info_change = TRUE;
  133.     side->cursor_change = TRUE;
  134. }
  135.  
  136. /* Given a side, get its relative position in array of sides (the "number"). */
  137. /* Neutrals are -1, for lack of any better ideas. */
  138.  
  139. side_number(side)
  140. Side *side;
  141. {
  142.     return (side == NULL ? -1 : (side - sides));
  143. }
  144.  
  145. /* The inverse function - given a number, figure out which side it is. */
  146. /* Return NULL for failure; hopefully callers will check on this! */
  147.  
  148. Side *
  149. side_n(n)
  150. int n;
  151. {
  152.     return ((n >= 0 && n < numsides) ? &sides[n] : (Side *)NULL);
  153. }
  154.  
  155. /* Put the given unit on the given side, without all the fancy effects. */
  156. /* Important to handle neutrals, because this gets called during init. */
  157.  
  158. extern bool sidecountsread;
  159.  
  160. assign_unit_to_side(unit, side)
  161. Unit *unit;
  162. Side *side;
  163. {
  164.     unit->side = side;
  165.     if (!sidecountsread)
  166.     unit->number = (side != NULL ? (side->counts)[unit->type]++ : 0);
  167. }
  168.  
  169. /* Being at war requires only ones of the sides to consider itself so. */
  170.  
  171. enemy_side(s1, s2)
  172. Side *s1, *s2;
  173. {
  174.     if (s1 == s2) return FALSE;
  175.     return (s1 != NULL && s2 != NULL &&
  176.         (s1->attitude[side_number(s2)] <= ENEMY ||
  177.          s2->attitude[side_number(s1)] <= ENEMY));
  178. }
  179.  
  180. /* A formal alliance requires the agreement of both sides. */
  181.  
  182. allied_side(s1, s2)
  183. Side *s1, *s2;
  184. {
  185.     if (s1 == s2) return TRUE;
  186.     return (s1 != NULL && s2 != NULL &&
  187.         s1->attitude[side_number(s2)] >= ALLY &&
  188.         s2->attitude[side_number(s1)] >= ALLY);
  189. }
  190.  
  191. /* Neutralness is basically anything else. */
  192.  
  193. neutral_side(s1, s2)
  194. Side *s1, *s2;
  195. {
  196.     return (!enemy_side(s1, s2) && !allied_side(s1, s2));
  197. }
  198.  
  199. /* Formal declarations of war need to do a transitive closure, as part of */
  200. /* dragging allies in. */
  201.  
  202. declare_war(side1, side2)
  203. Side *side1, *side2;
  204. {
  205.     Side *side3;
  206.  
  207.     notify_all("The %s and the %s have declared war!!",
  208.            copy_string(plural_form(side1->name)),
  209.            copy_string(plural_form(side2->name)));
  210.     make_war(side1, side2);
  211.     for_all_sides(side3) {
  212.     if (allied_side(side3, side1)) make_war(side3, side2);
  213.     if (allied_side(side3, side2)) make_war(side3, side1);
  214.     }
  215. }
  216.  
  217. /* Internal non-noisy function. */
  218.  
  219. make_war(side1, side2)
  220. Side *side1, *side2;
  221. {
  222.     side1->attitude[side_number(side2)] = ENEMY;
  223.     side2->attitude[side_number(side1)] = ENEMY;
  224. }
  225.  
  226. /* Establish neutrality for both sides. */
  227.  
  228. declare_neutrality(side1, side2)
  229. Side *side1, *side2;
  230. {
  231.     notify_all("The %s and the %s have agreed to neutrality.",
  232.            copy_string(plural_form(side1->name)),
  233.            copy_string(plural_form(side2->name)));
  234.     make_neutrality(side1, side2);
  235. }
  236.  
  237. /* Internal non-noisy function. */
  238.  
  239. make_neutrality(side1, side2)
  240. Side *side1, *side2;
  241. {
  242.     side1->attitude[side_number(side2)] = NEUTRAL;
  243.     side2->attitude[side_number(side1)] = NEUTRAL;
  244. }
  245.  
  246. /* Establish the alliance for both sides, then extend it to include */
  247. /* every other ally (only need one pass over sides to ensure transitive */
  248. /* closure, because alliances formed one at a time). */
  249.  
  250. declare_alliance(side1, side2)
  251. Side *side1, *side2;
  252. {
  253.     Side *side3;
  254.  
  255.     notify_all("The %s and the %s enter into an alliance.",
  256.            copy_string(plural_form(side1->name)),
  257.            copy_string(plural_form(side2->name)));
  258.     make_alliance(side1, side2);
  259.     for_all_sides(side3) {
  260.     if (allied_side(side3, side1)) make_alliance(side3, side2);
  261.     if (allied_side(side3, side2)) make_alliance(side3, side1);
  262.     }
  263. }
  264.  
  265. /* Internal non-noisy function. */
  266.  
  267. make_alliance(side1, side2)
  268. Side *side1, *side2;
  269. {
  270.     if (side1 != side2) {
  271.     side1->attitude[side_number(side2)] = ALLY;
  272.     side2->attitude[side_number(side1)] = ALLY;
  273.     }
  274. }
  275.  
  276. /* General method for passing along info about one side to another. */
  277. /* If sender is NULL, it means to pass along info about *all* sides. */
  278.  
  279. reveal_side(sender, recipient, chance)
  280. Side *sender, *recipient;
  281. int chance;
  282. {
  283.     Unit *unit;
  284.  
  285.     for_all_units(unit) {
  286.     if (alive(unit) &&
  287.         (unit->side == sender || sender == NULL) &&
  288.         probability(chance)) {
  289.         if (see_exact(recipient, unit->x, unit->y))
  290.             draw_hex(recipient, unit->x, unit->y, TRUE);
  291.     }
  292.     }
  293. }
  294.  
  295. /* An always-seen unit has builtin spies to inform of movements. */
  296. /* When such a unit occupies a hex, coverage is turned on and remains */
  297. /* on until the unit leaves that hex. */
  298.  
  299. all_see_occupy(unit, x, y)
  300. Unit *unit;
  301. int x, y;
  302. {
  303.     Side *side;
  304.  
  305.     if (utypes[unit->type].seealways) {
  306.     for_all_sides(side) {
  307.         if (side_view(side, x, y) != UNSEEN) {
  308.         add_cover(side, x, y, 100);
  309.         see_hex(side, x, y);
  310.         }
  311.     }
  312.     }
  313. }
  314.  
  315. /* Departure results in coverage being decremented, AFTER the side sees */
  316. /* that the hex is now empty. */
  317.  
  318. all_see_leave(unit, x, y)
  319. Unit *unit;
  320. int x, y;
  321. {
  322.     Side *side;
  323.  
  324.     if (utypes[unit->type].seealways) {
  325.     for_all_sides(side) {
  326.         if (side_view(side, x, y) != UNSEEN) {
  327.         see_hex(side, x, y);
  328.         add_cover(side, x, y, -100);
  329.         }
  330.     }
  331.     }
  332. }
  333.  
  334. /* Unit's beady eyes are now covering the immediate area.  The iteration */
  335. /* covers a hex area;  since new things may be coming into view, we have */
  336. /* to check and maybe draw lots of hexes (but only need the one flush, */
  337. /* fortunately). */
  338.  
  339. cover_area(unit, x0, y0, onoff)
  340. Unit *unit;
  341. int x0, y0, onoff;
  342. {
  343.     int u = unit->type, range, x, y, x1, y1, x2, y2, best, diff, dist, cov;
  344.     Unit *eunit;
  345.     Side *side = unit->side;
  346.  
  347.     if (neutral(unit) || period.allseen) return;
  348.     range = utypes[u].seerange;
  349.     best = utypes[u].seebest;
  350.     diff = best - utypes[u].seeworst;
  351.     y1 = y0 - range;
  352.     y2 = y0 + range;
  353.     for (y = y1; y <= y2; ++y) {
  354.     if (between(0, y, world.height-1)) {
  355.         x1 = x0 - (y < y0 ? (y - y1) : range);
  356.         x2 = x0 + (y > y0 ? (y2 - y) : range);
  357.         for (x = x1; x <= x2; ++x) {
  358.         dist = distance(x0, y0, x, y);
  359.         cov = (onoff * (best - (dist * diff) / range)) +
  360.             cover(side, wrap(x), y);
  361.         set_cover(side, wrap(x), y, max(0, cov));
  362.         if (onoff > 0 && see_hex(side, wrap(x), y)) {
  363.             if ((eunit = unit_at(wrap(x), y)) != NULL) {
  364.             if (unit->orders.flags & ENEMYWAKE)
  365.                 if (!allied_side(eunit->side, side))
  366.                 wake_unit(unit, TRUE);
  367.             }
  368.         }
  369.         }
  370.     }
  371.     }
  372.     if (onoff > 0 && active_display(side)) flush_output(side);
  373. }
  374.  
  375. /* Update the view of this hex for everybody's benefit.  May have to write */
  376. /* to many displays, sigh. */
  377.  
  378. all_see_hex(x, y)
  379. int x, y;
  380. {
  381.     register Side *side;
  382.  
  383.     for_all_sides(side) see_hex(side, x, y);
  384. }
  385.  
  386. /* Look at the given position, possibly not seeing anything.  Return true if */
  387. /* a unit was spotted. */
  388.  
  389. see_hex(side, x, y)
  390. Side *side;
  391. int x, y;
  392. {
  393.     register bool yes = FALSE;
  394.     register int u, chance, newview, terr;
  395.     register Unit *unit;
  396.  
  397.     if (side == NULL) return FALSE;
  398.     if (cover(side, x, y) > 0) {
  399.     if ((unit = unit_at(x, y)) != NULL) {
  400.         u = unit->type;
  401.         if (unit->side == side) {
  402.         yes = TRUE;
  403.         } else {
  404.         chance = (cover(side, x, y) * utypes[u].visibility) / 100;
  405.         terr = terrain_at(x, y);
  406.         chance = (chance * (100 - utypes[u].conceal[terr])) / 100;
  407.         if (probability(chance)) yes = TRUE;
  408.         }
  409.         if (yes) {
  410.         newview = buildview(side_number(unit->side), u);
  411.         if (set_side_view(side, x, y, newview))
  412.             draw_hex(side, x, y, FALSE);
  413.         return TRUE;
  414.         } else {
  415.         return FALSE;
  416.         }
  417.     } else {
  418.         if (set_side_view(side, x, y, EMPTY))
  419.             draw_hex(side, x, y, FALSE);
  420.         return FALSE;
  421.     }
  422.     } else {
  423.     /* preserve old image */
  424.     return FALSE;
  425.     }
  426. }
  427.  
  428. /* "Bare-bones" viewing, for whenever you know exactly what's there. */
  429. /* This is the lowest level of all viewing routines, and executed a *lot*. */
  430.  
  431. bool
  432. see_exact(side, x, y)
  433. Side *side;
  434. int x, y;
  435. {
  436.     register int newview;
  437.     register Unit *unit = unit_at(x, y);
  438.  
  439.     if (side == NULL) return;
  440.     newview = (unit ? buildview(side_number(unit->side), unit->type) : EMPTY);
  441.     return (set_side_view(side, x, y, newview));
  442. }
  443.  
  444. /* Utility to clean up images of units from a lost side. */
  445.  
  446. remove_images(side, n)
  447. Side *side;
  448. int n;
  449. {
  450.     int x, y, view;
  451.  
  452.     for (x = 0; x < world.width; ++x) {
  453.     for (y = 0; y < world.height; ++y) {
  454.         view = side_view(side, x, y);
  455.         if (view != EMPTY && view != UNSEEN && vside(view) == n) {
  456.         if (set_side_view(side, x, y, EMPTY))
  457.             draw_hex(side, x, y, TRUE);
  458.         }
  459.     }
  460.     }
  461. }
  462.  
  463. /* Show some overall numbers on performance of a side. */
  464.  
  465. print_side_results(fp, side)
  466. FILE *fp;
  467. Side *side;
  468. {
  469.     fprintf(fp, "The %s (%s):\n",
  470.         plural_form(side->name), (side->host ? side->host : "machine"));
  471.     fprintf(fp, "\n");
  472. }
  473.  
  474. /* Display what is essentially a double-column bookkeeping of unit gains */
  475. /* and losses.  Tricks here include the use of "dummy reason" flags to */
  476. /* display sums of several columns. */
  477.  
  478. print_unit_record(fp, side)
  479. FILE *fp;
  480. Side *side;
  481. {
  482.     int atype, reason, sum;
  483.  
  484.     fprintf(fp, "Unit Record (gains and losses by cause and unit type)\n");
  485.     fprintf(fp, "   ");
  486.     for (reason = 0; reason < NUMREASONS; ++reason) {
  487.     fprintf(fp, " %3s", reasonnames[reason]);
  488.     }
  489.     fprintf(fp, "  Total\n");
  490.     for_all_unit_types(atype) {
  491.     sum = 0;
  492.     fprintf(fp, " %c ", utypes[atype].uchar);
  493.     for (reason = 0; reason < NUMREASONS; ++reason) {
  494.         if (side->balance[atype][reason] > 0) {
  495.         fprintf(fp, " %3d", side->balance[atype][reason]);
  496.         sum += side->balance[atype][reason];
  497.         } else if (reason == DUMMYREAS) {
  498.         fprintf(fp, " %3d", sum);
  499.         sum = 0;
  500.         } else {
  501.         fprintf(fp, "    ");
  502.         }
  503.     }
  504.     fprintf(fp, "   %3d\n", sum);
  505.     }
  506.     fprintf(fp, "\n");
  507. }
  508.  
  509.  
  510. bool
  511. set_side_view(s,x,y,v)
  512. Side *s;
  513. int x,y,v;
  514. {
  515.     register int index = world.width * y + x;
  516.  
  517.     if ( s->view[index] == v)
  518.         return FALSE;
  519.     else {
  520.         s->view[index] = v;
  521.         return TRUE;
  522.     }
  523. }
  524.  
  525.